What is type-fest?
The type-fest package provides a collection of essential TypeScript types for use in a wide range of applications. It includes utility types, primitive types, and complex object types to enhance TypeScript's static typing capabilities.
What are type-fest's main functionalities?
Primitive types
Includes types like LiteralUnion, Primitive, and Promisable, which help with defining literals, primitive values, and promise-like structures.
{"isPrimitive": true}
Basic utilities
Provides utility types such as Except, Mutable, ReadonlyDeep, and many others that help manipulate and transform types in various ways.
{"isEmptyArray": array.length === 0}
Object types
Contains types for working with objects, such as Merge and RequireAtLeastOne, which assist in merging types and ensuring at least one property is present, respectively.
{"isObjectClean": Object.keys(object).length === 0 && object.constructor === Object}
Conditional types
Includes conditional types like ConditionalExcept and ConditionalKeys, which apply conditions to filter keys or properties of types.
{"isTruthy": T extends false | '' | 0 | null | undefined ? false : true}
Other packages similar to type-fest
utility-types
The utility-types package provides a collection of utility types for TypeScript, similar to type-fest. It includes types for operations like picking, omitting, and readonly transformations. It is comparable to type-fest but may have a different set of utilities and slightly different implementations.
ts-essentials
ts-essentials offers a wide range of TypeScript types, including deep readonly and writable types, as well as utility types for better type inference. It is similar to type-fest in its goal to enhance TypeScript's type system but may differ in the specific types offered and its API design.
typesafe-actions
While typesafe-actions is more focused on Redux action creators, it also provides utility types for better type safety in Redux. It is similar to type-fest in that it enhances TypeScript's type system but is more specialized for Redux-related typing.
A collection of essential TypeScript types
Many of the types here should have been built-in. You can help by suggesting some of them to the TypeScript project.
Either add this package as a dependency or copy-paste the needed types. No credit required. 👌
PR welcome for additional commonly needed types and docs improvements. Read the contributing guidelines first.
Install
$ npm install type-fest
Requires TypeScript >=3.2
Usage
import {Except} from 'type-fest';
type Foo = {
unicorn: string;
rainbow: boolean;
};
type FooWithoutRainbow = Except<Foo, 'rainbow'>;
API
Click the type names for complete docs.
Basic
Utilities
Except
- Create a type from an object type without certain keys. This is a stricter version of Omit
.Mutable
- Convert an object with readonly
keys into a mutable object. The inverse of Readonly<T>
.Merge
- Merge two types into a new type. Keys of the second type overrides keys of the first type.MergeExclusive
- Create a type that has mutually exclusive keys.RequireAtLeastOne
- Create a type that requires at least one of the given keys.RequireExactlyOne
- Create a type that requires exactly a single key of the given keys and disallows more.PartialDeep
- Create a deeply optional version of another type. Use Partial<T>
if you only need one level deep.ReadonlyDeep
- Create a deeply immutable version of an object
/Map
/Set
/Array
type. Use Readonly<T>
if you only need one level deep.LiteralUnion
- Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for Microsoft/TypeScript#29729.Promisable
- Create a type that represents either the value or the value wrapped in PromiseLike
.Opaque
- Create an opaque type.SetOptional
- Create a type that makes the given keys optional.SetRequired
- Create a type that makes the given keys required.
Miscellaneous
Declined types
If we decline a type addition, we will make sure to document the better solution here.
Diff
and Spread
- The PR author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider.Dictionary
- You only save a few characters (Dictionary<number>
vs Record<string, number>
) from Record
, which is more flexible and well-known. Also, you shouldn't use an object as a dictionary. We have Map
in JavaScript now.
Tips
Built-in types
There are many advanced types most users don't know about.
-
Partial<T>
- Make all properties in T
optional.
Example
Playground
interface NodeConfig {
appName: string;
port: number;
}
class NodeAppBuilder {
private configuration: NodeConfig = {
appName: 'NodeApp',
port: 3000
};
private updateConfig<Key extends keyof NodeConfig>(key: Key, value: NodeConfig[Key]) {
this.configuration[key] = value;
}
config(config: Partial<NodeConfig>) {
type NodeConfigKey = keyof NodeConfig;
for (const key of Object.keys(config) as NodeConfigKey[]) {
const updateValue = config[key];
if (updateValue === undefined) {
continue;
}
this.updateConfig(key, updateValue);
}
return this;
}
}
new NodeAppBuilder().config({appName: 'ToDoApp'});
-
Required<T>
- Make all properties in T
required.
Example
Playground
interface ContactForm {
email?: string;
message?: string;
}
function submitContactForm(formData: Required<ContactForm>) {
}
submitContactForm({
email: 'ex@mple.com',
message: 'Hi! Could you tell me more about…',
});
submitContactForm({
email: 'ex@mple.com',
});
-
Readonly<T>
- Make all properties in T
readonly.
Example
Playground
enum LogLevel {
Off,
Debug,
Error,
Fatal
};
interface LoggerConfig {
name: string;
level: LogLevel;
}
class Logger {
config: Readonly<LoggerConfig>;
constructor({name, level}: LoggerConfig) {
this.config = {name, level};
Object.freeze(this.config);
}
}
const config: LoggerConfig = {
name: 'MyApp',
level: LogLevel.Debug
};
const logger = new Logger(config);
logger.config.level = LogLevel.Error;
config.level = LogLevel.Error;
-
Pick<T, K>
- From T
, pick a set of properties whose keys are in the union K
.
Example
Playground
interface Article {
title: string;
thumbnail: string;
content: string;
}
type ArticlePreview = Pick<Article, 'title' | 'thumbnail'>;
function renderArticlePreviews(previews: ArticlePreview[]): HTMLElement {
const articles = document.createElement('div');
for (const preview of previews) {
}
return articles;
}
const articles = renderArticlePreviews([
{
title: 'TypeScript tutorial!',
thumbnail: '/assets/ts.jpg'
}
]);
-
Record<K, T>
- Construct a type with a set of properties K
of type T
.
Example
Playground
type MemberPosition = 'intern' | 'developer' | 'tech-lead';
interface Employee {
firstName: string;
lastName: string;
yearsOfExperience: number;
}
const team: Record<MemberPosition, Employee[]> = {
intern: [],
developer: [],
'tech-lead': [],
};
team.intern.push({
firstName: 'John',
lastName: 'Doe',
yearsOfExperience: 0
});
const teamEmpty: Record<MemberPosition, null> = {
intern: null,
developer: null,
};
-
Exclude<T, U>
- Exclude from T
those types that are assignable to U
.
Example
Playground
interface ServerConfig {
port: null | string | number;
}
type RequestHandler = (request: Request, response: Response) => void;
function getPortValue(port: Exclude<ServerConfig['port'], null>): number {
if (typeof port === 'string') {
return parseInt(port, 10);
}
return port;
}
function startServer(handler: RequestHandler, config: ServerConfig): void {
const server = require('http').createServer(handler);
const port = config.port === null ? 3000 : getPortValue(config.port);
server.listen(port);
}
-
Extract<T, U>
- Extract from T
those types that are assignable to U
.
Example
Playground
declare function uniqueId(): number;
const ID = Symbol('ID');
interface Person {
[ID]: number;
name: string;
age: number;
}
function changePersonData<
Obj extends Person,
Key extends Extract<keyof Person, string>,
Value extends Obj[Key]
> (obj: Obj, key: Key, value: Value): void {
obj[key] = value;
}
const andrew = {
[ID]: uniqueId(),
name: 'Andrew',
age: 0,
};
changePersonData(andrew, 'name', 'Pony');
changePersonData(andrew, ID, uniqueId());
-
NonNullable<T>
- Exclude null
and undefined
from T
.
Example
Works with strictNullChecks
set to true
. (Read more here)
Playground
type PortNumber = string | number | null;
class ServerBuilder {
portNumber!: NonNullable<PortNumber>;
port(this: ServerBuilder, port: PortNumber): ServerBuilder {
if (port == null) {
this.portNumber = 8000;
} else {
this.portNumber = port;
}
return this;
}
}
const serverBuilder = new ServerBuilder();
serverBuilder
.port('8000')
.port(null)
.port(3000);
serverBuilder.portNumber = null;
-
Parameters<T>
- Obtain the parameters of a function type in a tuple.
Example
Playground
function shuffle(input: any[]): void {
}
function callNTimes<Fn extends (...args: any[]) => any> (func: Fn, callCount: number) {
type FunctionParameters = Parameters<Fn>;
return function (...args: FunctionParameters) {
for (let i = 0; i < callCount; i++) {
func(...args);
}
}
}
const shuffleTwice = callNTimes(shuffle, 2);
-
ConstructorParameters<T>
- Obtain the parameters of a constructor function type in a tuple.
Example
Playground
class ArticleModel {
title: string;
content?: string;
constructor(title: string) {
this.title = title;
}
}
class InstanceCache<T extends (new (...args: any[]) => any)> {
private ClassConstructor: T;
private cache: Map<string, InstanceType<T>> = new Map();
constructor (ctr: T) {
this.ClassConstructor = ctr;
}
getInstance (...args: ConstructorParameters<T>): InstanceType<T> {
const hash = this.calculateArgumentsHash(...args);
const existingInstance = this.cache.get(hash);
if (existingInstance !== undefined) {
return existingInstance;
}
return new this.ClassConstructor(...args);
}
private calculateArgumentsHash(...args: any[]): string {
return 'hash';
}
}
const articleCache = new InstanceCache(ArticleModel);
const amazonArticle = articleCache.getInstance('Amazon forests burining!');
-
ReturnType<T>
– Obtain the return type of a function type.
Example
Playground
function mapIter<
Elem,
Func extends (elem: Elem) => any,
Ret extends ReturnType<Func>
>(iter: Iterable<Elem>, callback: Func): Ret[] {
const mapped: Ret[] = [];
for (const elem of iter) {
mapped.push(callback(elem));
}
return mapped;
}
const setObject: Set<string> = new Set();
const mapObject: Map<number, string> = new Map();
mapIter(setObject, (value: string) => value.indexOf('Foo'));
mapIter(mapObject, ([key, value]: [number, string]) => {
return key % 2 === 0 ? value : 'Odd';
});
-
InstanceType<T>
– Obtain the instance type of a constructor function type.
Example
Playground
class IdleService {
doNothing (): void {}
}
class News {
title: string;
content: string;
constructor(title: string, content: string) {
this.title = title;
this.content = content;
}
}
const instanceCounter: Map<Function, number> = new Map();
interface Constructor {
new(...args: any[]): any;
}
function getInstance<
Constr extends Constructor,
Args extends ConstructorParameters<Constr>
>(constructor: Constr, ...args: Args): InstanceType<Constr> {
let count = instanceCounter.get(constructor) || 0;
const instance = new constructor(...args);
instanceCounter.set(constructor, count + 1);
console.log(`Created ${count + 1} instances of ${Constr.name} class`);
return instance;
}
const idleService = getInstance(IdleService);
const newsEntry = getInstance(News, 'New ECMAScript proposals!', 'Last month...');
-
Omit<T, K>
– Constructs a type by picking all properties from T and then removing K.
Example
Playground
interface Animal {
imageUrl: string;
species: string;
images: string[];
paragraphs: string[];
}
type AnimalShortInfo = Omit<Animal, 'images' | 'paragraphs'>;
function renderAnimalHoverInfo (animals: AnimalShortInfo[]): HTMLElement {
const container = document.createElement('div');
return container;
}
You can find some examples in the TypeScript docs.
Maintainers
License
(MIT OR CC0-1.0)